package com.smartum.mpr.services;

import java.util.List;

import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.map.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;

import com.smartum.mpr.business.ItemBusiness;
import com.smartum.mpr.business.ItemImageBusiness;
import com.smartum.mpr.business.StaticDataBusiness;
import com.smartum.mpr.business.UserBusiness;
import com.smartum.mpr.dao.ItemDao;
import com.smartum.mpr.exception.NotExistsImageException;
import com.smartum.mpr.exception.NotExistsItemException;
import com.smartum.mpr.exception.NotExistsSubCategoryException;
import com.smartum.mpr.exception.NotExistsUserException;
import com.smartum.mpr.model.Item;
import com.smartum.mpr.model.ItemImage;
import com.smartum.mpr.model.ItemSubCategory;
import com.smartum.mpr.model.ItemType;
import com.smartum.mpr.model.User;
import com.smartum.mpr.store.local.ItemImageProvider;
import com.smartum.mpr.validators.EmailValidator;

@Controller
@RequestMapping("/item")
public class ItemService extends BaseService<Item> {

	@Autowired
	private ItemBusiness itemBusiness;
	@Autowired
	private StaticDataBusiness staticDataBusiness;
	@Autowired
	private UserBusiness userBusiness;
	@Autowired
	private ItemImageBusiness itemImageBusiness;

	@RequestMapping(value = "/get/one", method = RequestMethod.POST)
	public ResponseEntity<String> getOneItemById(@RequestBody String json) {
		LOGGER_API.info("request: get one item- " + json);
		try {
			checkRequestPermissions(json);
			String request = extractRequestStringData(json);
			ObjectMapper mapper = getTargetParser().getMapper();
			JsonNode requestNode = mapper.readTree(request);
			Long itemId = requestNode.get("item_id").asLong();

			Item item = itemBusiness.getItem(itemId);
			ResponseEntity<String> response;
			if (item == null) {
				throw new NotExistsItemException("with id " + itemId);
			}
			response = getResponseInJsonType(generateSuccessJson(getTargetParser().writeEntity(item)), HttpStatus.OK);
			LOGGER_API.info("response : get one item - OK");
			logResponse(response);
			return response;

		} catch (Exception e) {
			LOGGER_API.error("response : get one item", e);
			return handleException(e);
		}

	}

	@RequestMapping(value = "/get/user", method = RequestMethod.POST)
	public ResponseEntity<String> getUserItems(@RequestBody String json) {
		LOGGER_API.info("request: get user items- " + json);
		try {

			String request = extractRequestStringData(json);
			ObjectMapper mapper = getTargetParser().getMapper();
			JsonNode requestNode = mapper.readTree(request);
			Long timestamp = requestNode.get("timestamp").asLong();
			int amount = requestNode.get("amount").asInt();

			User user = null;
			
			if(requestNode.get("user_id")==null){
				String token = extractTokenStringData(json);
				user = userBusiness.getUserByToken(token);
			}else{
				checkRequestPermissions(json);
				long userId = requestNode.get("user_id").asLong();
				user = userBusiness.getById(userId);
			}
			
			if(user==null){
				throw new NotExistsUserException();
			}

			
			List<Item> items = itemBusiness.getUserItems(user.getId(), timestamp, amount);
			ResponseEntity<String> response = getResponseInJsonType(generateSuccessJson(getTargetParser()
			        .writeEntityList(items)), HttpStatus.OK);
			LOGGER_API.info("request: get user items - OK");
			logResponse(response);
			return response;
		} catch (Exception e) {
			LOGGER_API.error("request: get user items", e);
			return handleException(e);
		}

	}

	@RequestMapping(value = "/update", method = RequestMethod.POST)
	public ResponseEntity<String> updateItem(@RequestBody String json) {
		LOGGER_API.info("request: update item - " + json);
		try {
			String token = extractTokenStringData(json);
			String request = extractRequestStringData(json);
			ObjectMapper mapper = getTargetParser().getMapper();

			User owner = userBusiness.getUserByToken(token);

			JsonNode requestNode = mapper.readTree(request);

			Long itemId = requestNode.get("item_id").asLong();

			Item item = itemBusiness.getItem(itemId);

			if (item == null) {
				throw new NotExistsItemException("with id: " + itemId);
			}

			if (requestNode.get("item_cost") != null) {
				item.setCost(requestNode.get("item_cost").asDouble());
			}
			if (requestNode.get("item_title") != null) {
				item.setTitle(requestNode.get("item_title").asText());
			}
			if (requestNode.get("item_description") != null) {
				item.setDescription(requestNode.get("item_description").asText());
			}

			if (requestNode.get("item_phone_number") != null) {
				item.setPhoneNumber(requestNode.get("item_phone_number").asText());
			}
			if (requestNode.get("item_subcategory_id") != null) {
				Long itemSubCategoryId = requestNode.get("item_subcategory_id").asLong();
				item.setSubCategory(staticDataBusiness.getItemSubCategoryById(itemSubCategoryId));
			}
			if (requestNode.get("item_county_id") != null) {
				Long itemCountyId = requestNode.get("item_county_id").asLong();
				item.setCounty(staticDataBusiness.getCountyById(itemCountyId));
			}
			if (requestNode.get("item_type") != null) {
				int itemTypeId = requestNode.get("item_type").asInt();
				item.setItemType(ItemType.getItemTypeById(itemTypeId));
			}
			if (requestNode.get("item_email") != null) {
				String itemEmail = requestNode.get("item_email").asText();
				new EmailValidator().validate(itemEmail);
				item.setItemEmail(itemEmail);
			}

			item.setTimeStamp(System.currentTimeMillis());

			itemBusiness.saveItem(item);
			LOGGER_API.info("request: update item - OK");
			return new ResponseEntity<String>(HttpStatus.OK);
		} catch (Exception e) {
			LOGGER_API.error("request: update item", e);
			return handleException(e);
		}
	}

	@RequestMapping(value = "/photo/add", method = RequestMethod.POST)
	public ResponseEntity<String> addImage(@RequestParam("json") String json, @RequestParam("photo") MultipartFile photo) {
		LOGGER_API.info("request: add image - " + json);
		try {
			String token = extractTokenStringData(json);
			userBusiness.getUserByToken(token);

			String request = extractRequestStringData(json);
			ObjectMapper mapper = getTargetParser().getMapper();
			JsonNode requestNode = mapper.readTree(request);
			Long itemId = requestNode.get("item_id").asLong();

			Item item = itemBusiness.getItem(itemId);
			if (item == null) {
				throw new NotExistsItemException("with id: " + itemId);
			}

			ItemImage itemImage = new ItemImage();
			itemImage.setImagePath("stub");
			itemImage.setImageTimestamp(System.currentTimeMillis());
			itemImage.setItem(item);

			if (requestNode.get("image_id") != null) {
				Long photoId = requestNode.get("image_id").asLong();
				itemImage.setId(photoId);
				(new ItemImageProvider()).deleteImage(photoId);
			}

			itemImageBusiness.saveItemImage(itemImage);

			String itemImagePath = (new ItemImageProvider()).storeImage(photo, itemImage.getId());
			itemImage.setImagePath(itemImagePath);
			itemImageBusiness.saveItemImage(itemImage);

			itemBusiness.changeImagePathInItemImage(itemImage);
			ResponseEntity<String> response = getResponseInJsonType(
			        generateSuccessJson(getParserByEntityClass(ItemImage.class).writeEntity(itemImage)), HttpStatus.OK);
			LOGGER_API.info("request: add image- OK");
			logResponse(response);
			return response;
		} catch (Exception e) {
			LOGGER_API.error("request: add image", e);
			return handleException(e);
		}

	}

	@RequestMapping(value = "/photo/delete", method = RequestMethod.POST)
	public ResponseEntity<String> deleteImage(@RequestBody String json) {
		LOGGER_API.info("request: delete image- " + json);
		try {
			String token = extractTokenStringData(json);
			userBusiness.getUserByToken(token);

			String request = extractRequestStringData(json);
			ObjectMapper mapper = getTargetParser().getMapper();
			JsonNode requestNode = mapper.readTree(request);
			Long photoId = requestNode.get("photo_id").asLong();

			if (itemImageBusiness.getItemImage(photoId) == null) {
				throw new NotExistsImageException("with id " + photoId);
			}

			(new ItemImageProvider()).deleteImage(photoId);
			itemImageBusiness.removeItemImage(photoId);
			LOGGER_API.info("request: delete image - OK");
			return new ResponseEntity<String>(HttpStatus.OK);
		} catch (Exception e) {
			LOGGER_API.error("request: delete image", e);
			return handleException(e);
		}

	}

	@RequestMapping(value = "/delete", method = RequestMethod.POST)
	public ResponseEntity<String> deleteItem(@RequestBody String json) {
		LOGGER_API.info("request: delete item - " + json);
		try {
			String token = extractTokenStringData(json);
			userBusiness.getUserByToken(token);

			String request = extractRequestStringData(json);
			ObjectMapper mapper = getTargetParser().getMapper();
			JsonNode requestNode = mapper.readTree(request);
			Long itemId = requestNode.get("item_id").asLong();
			Item item = itemBusiness.getItem(itemId);
			if(item==null){
				throw new NotExistsItemException("with id: "+ itemId);
			}
			(new ItemImageProvider()).deleteImage(itemId);
			itemBusiness.deleteItem(itemId);
			LOGGER_API.info("request: delete item - OK");
			return new ResponseEntity<String>(HttpStatus.OK);
		} catch (Exception e) {
			LOGGER_API.error("request: delete item", e);
			return handleException(e);
		}

	}

	@RequestMapping(value = "/search", method = RequestMethod.POST)
	public ResponseEntity<String> searchItem(@RequestBody String json) {
		LOGGER_API.info("request: search items - " + json);
		try {
			checkRequestPermissions(json);

			String request = extractRequestStringData(json);
			ObjectMapper mapper = getTargetParser().getMapper();
			JsonNode requestNode = mapper.readTree(request);
			Long timestamp = requestNode.get("timestamp").asLong();
			int amount = requestNode.get("amount").asInt();

			Long categoryId = null;
			Long subCategoryId = null;
			Long countyId = null;
			String priceSorting = null;

			if (requestNode.get("category_id") != null) {
				categoryId = requestNode.get("category_id").asLong();
			}

			if (requestNode.get("subcategory_id") != null) {
				subCategoryId = requestNode.get("subcategory_id").asLong();
			}

			if (requestNode.get("price") != null) {
				priceSorting = requestNode.get("price").asText();
			}

			if (requestNode.get("county_id") != null) {
				countyId = requestNode.get("county_id").asLong();
			}

			Boolean getHeighest = null;

			if (priceSorting != null) {

				if (priceSorting.equals("heighest")) {
					getHeighest = true;
				} else if (priceSorting.equals("lowest")) {
					getHeighest = false;
				}

			}
			ResponseEntity<String> responseEntity = getResponseInJsonType(
			        generateSuccessJson(getTargetParser().writeEntityList(
			                itemBusiness.searchItems(categoryId, subCategoryId, getHeighest, timestamp, amount,
			                        countyId))), HttpStatus.OK);
			LOGGER_API.info("request: search items - OK");
			logResponse(responseEntity);
			return responseEntity;
		} catch (Exception e) {
			LOGGER_API.error("request: search items", e);
			return handleException(e);
		}

	}

	@RequestMapping(value = "/post", method = RequestMethod.POST)
	public ResponseEntity<String> saveItem(@RequestParam("json") String json, @RequestParam("photo") MultipartFile image) {
		LOGGER_API.info("request: post item - " + json);
		try {
			String token = extractTokenStringData(json);
			String request = extractRequestStringData(json);

			User owner = userBusiness.getUserByToken(token);

			
			ObjectMapper mapper = getTargetParser().getMapper();
			JsonNode requestNode = mapper.readTree(request);

			Double itemCost = requestNode.get("item_cost").asDouble();
			String itemTitle = requestNode.get("item_title").asText();
			String itemDescription = requestNode.get("item_description").asText();
			String itemPhoneNumber = requestNode.get("item_phone_number").asText();
			Long itemSubCategoryId = requestNode.get("item_subcategory_id").asLong();
			Long itemCountyId = requestNode.get("item_county_id").asLong();
			Integer itemTypeId = requestNode.get("item_type").asInt();
			String itemEmail = requestNode.get("item_email").asText();

			ItemSubCategory subCategory = staticDataBusiness.getItemSubCategoryById(itemSubCategoryId);
			if(subCategory==null){
				throw new NotExistsSubCategoryException();
			}
			
			itemBusiness.checkPostPermission(owner.getId(), subCategory.getCategory().getId());
			
			new EmailValidator().validate(itemEmail);

			Item item = new Item();
			item.setSubCategory(staticDataBusiness.getItemSubCategoryById(itemSubCategoryId));
			item.setCounty(staticDataBusiness.getCountyById(itemCountyId));
			item.setCost(itemCost);
			item.setDescription(itemDescription);
			item.setPhoneNumber(itemPhoneNumber);
			item.setTitle(itemTitle);
			item.setOwner(owner);
			item.setTimeStamp(System.currentTimeMillis());
			item.setItemEmail(itemEmail);
			item.setItemType(ItemType.getItemTypeById(itemTypeId));

			itemBusiness.saveItem(item);

			ItemImage itemImage = new ItemImage();
			itemImage.setImagePath("stub");
			itemImage.setImageTimestamp(System.currentTimeMillis());
			itemImage.setItem(item);
			itemImageBusiness.saveItemImage(itemImage);

			String itemImagePath = (new ItemImageProvider()).storeImage(image, itemImage.getId());

			itemImage.setImagePath(itemImagePath);
			itemImageBusiness.saveItemImage(itemImage);

			itemBusiness.removePostPermission(owner.getId(), subCategory.getCategory().getId());
			
			item = itemBusiness.getItem(item.getId());

			ResponseEntity<String> response = getResponseInJsonType(
			        generateSuccessJson(getTargetParser().writeEntity(item)), HttpStatus.OK);
			LOGGER_API.info("request: post item  - OK ");
			logResponse(response);

			return response;
		} catch (Exception e) {
			LOGGER_API.error("request: post item ", e);
			return handleException(e);
		}
	}

	@Override
	protected Class<Item> getEntityClass() {
		return Item.class;
	}

}
